package com.springboot.lock.distribute.aspect;

import com.springboot.lock.distribute.annotation.CacheLock;
import com.springboot.lock.distribute.key.CacheKeyGenerator;
import com.springboot.lock.distribute.redis.RedisLock;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.util.UUID;

/**
 * @Author: TongRui乀
 * @Date: 2019/1/25 16:58
 * @description： 方法拦截切面
 */
@Configuration
@Aspect
public class LockMethodAspect {

    @Autowired
    private CacheKeyGenerator cacheKeyGenerator;


    @Autowired
    private RedisLock redisLock;


    @Around("execution(public * *(..)) && @annotation(com.springboot.lock.distribute.annotation.CacheLock))")
    public Object interceptor(ProceedingJoinPoint pjp){

        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock lock = method.getAnnotation(CacheLock.class);
        if (StringUtils.isEmpty(lock.prefix())) {
            throw new RuntimeException("lock key don't null...");
        }
        final String lockKey = cacheKeyGenerator.getLockCacheKey(pjp);
        String value = UUID.randomUUID().toString();
        try {
            // 假设上锁成功，但是设置过期时间失效，以后拿到的都是 false
            final boolean success = redisLock.lock(lockKey, value, lock.expire(), lock.timeUnit());
            if (!success) {
                throw new RuntimeException("重复提交");
            }
            try {
                return pjp.proceed();
            } catch (Throwable throwable) {
                throw new RuntimeException("系统异常");
            }
        } finally {
            // TODO 如果演示的话需要注释该代码;实际应该放开
            redisLock.unlock(lockKey, value);
        }


    }

}
